package com.zhao.dota.config;

import com.zhao.dota.model.Permission;
import com.zhao.dota.security.UserDetailsServiceImpl;
import com.zhao.dota.security.filter.AuthenticationFilter;
import com.zhao.dota.security.filter.LoginFilter;
import com.zhao.dota.security.handler.*;
import com.zhao.dota.security.integration.IntegrationAuthenticationFilter;
import com.zhao.dota.service.PermissionService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private AccessDeniedHandler accessDeniedHandler;
    @Resource
    private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;
    @Resource
    private LoginSuccessHandler loginSuccessHandler;
    @Resource
    private LoginFailureHandler loginFailureHandler;
    @Resource
    private LogoutHandler logoutHandler;
    @Resource
    private PermissionService permissionService;


    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    @Bean
    @Primary
    public PasswordEncoder passwordEncoder() {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                return bCryptPasswordEncoder.encode(rawPassword);
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return encodedPassword == null || bCryptPasswordEncoder.matches(rawPassword, encodedPassword);
            }
        };
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(userDetailsService());
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        auth.authenticationProvider(daoAuthenticationProvider);
    }

    protected void configure(HttpSecurity http) throws Exception {
        List<Permission> list = permissionService.list();
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests();
        expressionInterceptUrlRegistry     // 对请求进行验证
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                // swagger2
                .antMatchers("/swagger**/**", "/v2/**", "/webjars/**").permitAll()
//                .antMatchers("**").permitAll()
//                .antMatchers("/login/getSteamLoginUrl", "/mine/**", "/import/**").hasRole("PLAYER")
                .and()
                .formLogin()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(entryPointUnauthorizedHandler)
                .accessDeniedHandler(accessDeniedHandler)
                .and()   //表示一个配置的结束
                .csrf().disable()
                .cors()
                .and()
                .logout()
                .logoutSuccessHandler(logoutHandler);

        list.stream().filter(p -> !p.getMenu()).filter(p -> StringUtils.hasText(p.getPath())).forEach(p -> {
            expressionInterceptUrlRegistry.antMatchers(p.getPath()).hasAuthority(p.getCode());
        });
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterBefore(integrationAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(loginFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Bean
    public LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter(authenticationManager());
        loginFilter.setAuthenticationSuccessHandler(loginSuccessHandler);
        loginFilter.setAuthenticationFailureHandler(loginFailureHandler);
        return loginFilter;
    }

    @Bean
    public AuthenticationFilter authenticationFilter() throws Exception {
        return new AuthenticationFilter(authenticationManager());
    }

    @Bean
    public LoginExpiredHandler loginExpiredHandler() {
        return new LoginExpiredHandler();
    }

    @Bean
    public IntegrationAuthenticationFilter integrationAuthenticationFilter() {
        return new IntegrationAuthenticationFilter();
    }

}
